package auth

import (
	"errors"
	"time"

	"github.com/golang-jwt/jwt/v4"
)

// JWTConfig JWT配置
type JWTConfig struct {
	Secret           string        // JWT密钥
	AccessExpiry     time.Duration // 访问令牌过期时间
	RefreshExpiry    time.Duration // 刷新令牌过期时间
	Issuer           string        // 签发者
	AccessTokenType  string        // 访问令牌类型
	RefreshTokenType string        // 刷新令牌类型
}

// DefaultJWTConfig 默认JWT配置
func DefaultJWTConfig() *JWTConfig {
	return &JWTConfig{
		Secret:           "saltadmin_secret_key", // 生产环境应该使用环境变量或配置文件
		AccessExpiry:     time.Hour * 2,          // 2小时
		RefreshExpiry:    time.Hour * 24 * 7,     // 7天
		Issuer:           "saltadmin",
		AccessTokenType:  "access",
		RefreshTokenType: "refresh",
	}
}

// JWTService JWT服务接口
type JWTService interface {
	// GenerateToken 生成令牌
	GenerateToken(userID, tenantID uint, username string) (*TokenInfo, error)
	// ValidateToken 验证令牌
	ValidateToken(tokenString string) (*Claims, error)
	// RefreshToken 刷新令牌
	RefreshToken(refreshToken string) (*TokenInfo, error)
}

// Claims JWT声明
type Claims struct {
	UserID    uint   `json:"user_id"`
	TenantID  uint   `json:"tenant_id"`
	Username  string `json:"username"`
	TokenType string `json:"token_type"`
	jwt.RegisteredClaims
}

// DefaultJWTService 默认JWT服务实现
type DefaultJWTService struct {
	config *JWTConfig
}

// NewJWTService 创建JWT服务
func NewJWTService(config *JWTConfig) JWTService {
	if config == nil {
		config = DefaultJWTConfig()
	}
	return &DefaultJWTService{config: config}
}

// GenerateToken 生成令牌
func (s *DefaultJWTService) GenerateToken(userID, tenantID uint, username string) (*TokenInfo, error) {
	// 生成访问令牌
	accessToken, err := s.generateTokenWithType(userID, tenantID, username, s.config.AccessTokenType, s.config.AccessExpiry)
	if err != nil {
		return nil, err
	}

	// 生成刷新令牌
	refreshToken, err := s.generateTokenWithType(userID, tenantID, username, s.config.RefreshTokenType, s.config.RefreshExpiry)
	if err != nil {
		return nil, err
	}

	return &TokenInfo{
		AccessToken:  accessToken,
		RefreshToken: refreshToken,
		ExpiresIn:    int(s.config.AccessExpiry.Seconds()),
		TokenType:    "Bearer",
	}, nil
}

// 生成指定类型的令牌
func (s *DefaultJWTService) generateTokenWithType(userID, tenantID uint, username, tokenType string, expiry time.Duration) (string, error) {
	now := time.Now()
	claims := &Claims{
		UserID:    userID,
		TenantID:  tenantID,
		Username:  username,
		TokenType: tokenType,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(now.Add(expiry)),
			IssuedAt:  jwt.NewNumericDate(now),
			NotBefore: jwt.NewNumericDate(now),
			Issuer:    s.config.Issuer,
		},
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString([]byte(s.config.Secret))
}

// ValidateToken 验证令牌
func (s *DefaultJWTService) ValidateToken(tokenString string) (*Claims, error) {
	// 解析令牌
	token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (interface{}, error) {
		// 验证签名算法
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, errors.New("unexpected signing method")
		}
		return []byte(s.config.Secret), nil
	})

	if err != nil {
		return nil, err
	}

	// 验证令牌有效性
	if !token.Valid {
		return nil, errors.New("invalid token")
	}

	// 获取声明
	claims, ok := token.Claims.(*Claims)
	if !ok {
		return nil, errors.New("invalid token claims")
	}

	return claims, nil
}

// RefreshToken 刷新令牌
func (s *DefaultJWTService) RefreshToken(refreshToken string) (*TokenInfo, error) {
	// 验证刷新令牌
	claims, err := s.ValidateToken(refreshToken)
	if err != nil {
		return nil, err
	}

	// 检查令牌类型
	if claims.TokenType != s.config.RefreshTokenType {
		return nil, errors.New("invalid token type")
	}

	// 生成新令牌
	return s.GenerateToken(claims.UserID, claims.TenantID, claims.Username)
}
